package apof.services
{
	import mx.collections.ArrayCollection;
	import apof.model.User;
	import apof.dao.Dao;
	import apof.model.Transection;
	import apof.model.Structure;
	import apof.model.ConsumeType;
	import apof.model.StructureItem;
	import apof.model.ChainStrcture;
	
	public class AnalysisService
	{
		/***************************************************************
		 *  static tools 
		 * **************************************************************/
		public static var MONTH_NAME:Array=[
			"Jan","Feb","Mar","Apr","May","Jun","July","Aug","Sep","Oct","Nov","Dec"
		]
		private static function cutTime(day:Date):Date {
			day.setHours(0,0,0,0);
			return day;
		}

		/***************************************************************
		 *  vars 
		 * **************************************************************/
		private var user:User;
		public function AnalysisService(user:User) {
			this.user=user;
		}
		
		/***************************************************************
		 *  methods 
		 * **************************************************************/
		public function getConsumeInfoInMonth():ArrayCollection{
			
			var list:ArrayCollection=new ArrayCollection();
			var num:Number;
			
			var lastDay:Date=new Date();
			lastDay=cutTime(lastDay);
			lastDay.month+=1;
			lastDay.fullYear-=1;
			lastDay.setDate(1);
			var firstDay:Date=new Date(lastDay.time);
			firstDay.month-=1;
			for(var i:int=0;i<12;i++) {
				num=getPersonalConsumeSum(firstDay,lastDay,-1);
				list.addItem({year:firstDay.fullYear,month:MONTH_NAME[firstDay.month],total:num});
				firstDay.month+=1;
				lastDay.month+=1;
			}
			return list;
		}
		
		public function getConsumeInfoInDay(year:int, month:int):ArrayCollection {
			var list:ArrayCollection=new ArrayCollection();
			var num:Number;
			
			var firstDay:Date=new Date(year,month-1);
			var lastDay:Date=new Date(firstDay.time);
			lastDay.date+=1;
			for(;lastDay.date>1;){
				num=getPersonalConsumeSum(firstDay,lastDay,-1);
				list.addItem({day:""+firstDay.date,total:num});
				firstDay.date+=1;
				lastDay.date+=1;
			}
			return list;
		}
		
		/***
		 * cns=-1:只统计支出
		 * cns=1:只统计收入
		 * cns=0:统计收支代数和
		 * **/
		private function getPersonalConsumeSum(st:Date,ed:Date,cns:int):Number{
			var filter:Function=function(tr:Transection,...rest):Boolean {
				return tr.time.time>=st.time
					&& tr.time.time<ed.time
					&& (cns==0 || cns*tr.amount>0);
			}
			var trList:Array=Dao.dp.retriveAll(Transection,null,null,filter);
			var sum:Number=0;
			trList.forEach(function(tr:Transection,...rest):void{
				if(cns!=0)sum+=Math.abs(tr.amount);
				else sum+=tr.amount;
			});
			return sum;
		}
		
		public function getUserIncome():Number {
			var firstDay:Date=new Date();
			cutTime(firstDay);
			firstDay.month-=1;
			firstDay.date=0;
			var lastDay:Date=new Date(firstDay.time);
			lastDay.month+=1;
			return getPersonalConsumeSum(firstDay,lastDay,1);
		}
		public function getUserExpense():Number {
			var firstDay:Date=new Date();
			cutTime(firstDay);
			firstDay.month-=1;
			firstDay.date=0;
			var lastDay:Date=new Date(firstDay.time);
			lastDay.month+=1;
			return getPersonalConsumeSum(firstDay,lastDay,-1);
		}
		
		
		public function getUserConsumeStructureByMonth(month:int):ChainStrcture {
			var ct:ConsumeType=Dao.dp.retrive(ConsumeType,0) as ConsumeType;
			var stc:ChainStrcture=generateCategoryConsumeStructure(user.uid,ct,function(item:Transection,...rest):Boolean {
				return item.time.month==month-1;
			});
			return stc;
		}
		
		public function getUserConsumeStructureInYear():ChainStrcture {
			var ct:ConsumeType=Dao.dp.retrive(ConsumeType,0) as ConsumeType;
			var firstDay:Date=new Date();
			firstDay.fullYear-=1;
			var stc:ChainStrcture=generateCategoryConsumeStructure(user.uid,ct,function(item:Transection,...rest):Boolean {
				return item.time.time>=firstDay.time;
			});
			return stc;
		}
		
		/**
		 * 0:该用户
		1:同等收入水平
		2:同等消费水平
		4:公众----作废。
		 * **/
		public function getConsumeStructure(type:int):ChainStrcture {
			if(type==0)return generateUserConsumeStructure(user.uid);
			//产生虚拟用户的ID
			var vuid:int=type*100;
			if(type==1) vuid+=user.incomeLevel;
			if(type==2) vuid+=user.expenseLevel;
			return getVUserConsumeStructure(vuid);
		}
		
		public function generateUserConsumeStructure(uid:int):ChainStrcture {
			var stc:ChainStrcture;
			var ct:ConsumeType=Dao.dp.retrive(ConsumeType,1) as ConsumeType;
			stc=generateCategoryConsumeStructure(uid,ct);
			return stc;
		}
		
		private function generateCategoryConsumeStructure(uid:int, root:ConsumeType, filter:Function=null):ChainStrcture {
			var stc:ChainStrcture=new ChainStrcture;
			
			/* 统计本目录下直接条目 */
			var others:Array=Dao.dp.retriveAll(Transection,"ctid",root.ctid,
				function(tr:Transection,...rest):Boolean{
					return tr.account.uid==uid && (filter==null || filter(tr));
				});
			var othersSum:Number=0;
			for each(var tr:Transection in others) {othersSum+=-tr.amount;}
			stc.sum+=othersSum;
			stc.addItem({category:"uncategoried",number:othersSum,structure:null});
			
			/* 处理子目录 */
			for each(var sub:ConsumeType in root.subTypes) {
				var subStc:ChainStrcture=generateCategoryConsumeStructure(uid,sub,filter);
				if(subStc.sum<0)continue; //evil!
				stc.sum+=subStc.sum;
				stc.addItem({category:sub.name, number:subStc.sum, structure:subStc.length>0?subStc:null});
			}
				
			return stc;
		}
		
		/**
		 * 
		 * 虚拟用户id（vuid）编码规则：
		 * vuid为3位数，左起第一位为虚拟用户类别，（0:该用户		1:同等收入水平		2:同等消费水平		4:公众）
		 * 当用户类别为1或2时，左起第二三位为收入水平/消费水平的LevelID。
		 * 当用户类别为4时，第二三位为用户组的GroupID。
		 * **/
		public function getVUserConsumeStructure(vuid:int) :ChainStrcture{
			var stc:ChainStrcture=new ChainStrcture();
			var items:Array=Dao.dp.retriveAll(StructureItem,null,null,
				function(item:StructureItem,...rest):Boolean{
					return item.uid==vuid;
					},"amount"
				);
			for each (var item:StructureItem in items) {
				stc.addItem({category:item.consumeType.name,number:item.amount});
			}
			return stc;
		}
		
		/**
		 * groupType:
		 * 		1:同等收入水平
				2:同等消费水平
				4:公众
		 * **/
		public function getConsumeLevelDistribution(inOrEx:Boolean,groupType:int):Array {
			var data:Array=[
			//income
			[
				null,null,
				//2:同等消费水平(2k-4k)
				//	0		1k		2k		3k		4k		5k		6k		More
				[	3,		1,		2,		9,		11,		10,		6,		2],
				null,
				//4:公众
				//	0		2k		4k		6k		8k		10k		More
				[	31,		15,		29,		22,		11,		3,		1]
			],
			//Expense
			[	null,
				//1:同等收入水平(2k-4k)
				//	1.5		2k		2.5		3k		3.5		4k		More
				[	5,		7,		9,		6,		4,		2,		0],
				null,null,
				//4:公众
				//	0,		2k,		4k,		6k,		8k,		10k,	More
				[	0,		49,		42,		28,		12,		6,		5]
			]
			];
			var description:Array=[
			//income
			[
				null,null,
				//2:同等消费水平(2k-4k)
				[	"0",	"1k",	"2k",	"3k",	"4k",	"5k",	"6k",	"More"],
				null,
				//4:公众
				[	"0",	"2k",	"4k",	"6k",	"8k",	"10k",	"More"]
			],
			//Expense
			[	null,
				//1:同等收入水平(2k-4k)
				[	"1.5k",	"2k",	"2.5k",	"3k",	"3.5",	"4k",	"More"],
				null,null,
				//4:公众
				[	"0",	"2k",	"4k",	"6k",	"8k",	"10k",	"More"]
			]
			]
			var index1:int=inOrEx?0:1;
			var dataArr:Array=data[index1][groupType] as Array;
			var desArr:Array=description[index1][groupType] as Array;
			var r:Array=[];
			for(var i:int=0;i<desArr.length;i++) {
				r.push({level:desArr[i],number:dataArr[i]});
			}
			
			
			if(inOrEx ) {
				if(groupType==4) {
					r[1]["userIn"]=0;
					r[2]["userIn"]=50;
				}else {
					r[2]["user"]=0;
					r[3]["user"]=15;
				}
			}else {
				if(groupType==4) {
					r[2]["userEx"]=0;
					r[3]["userEx"]=50;
				}else {
					r[3]["user"]=0;
					r[4]["user"]=13;
				}
			}
			return r;
		}
		
		public function getPublicLevels():Array {
			var arrin:Array=getConsumeLevelDistribution(true,4);
			var arrex:Array=getConsumeLevelDistribution(false,4);
			var r:Array=new Array();
			for(var i:int=0;i<arrin.length;i++) {
				r[i]={};
				r[i].level=arrin[i].level;
				r[i].pubIn=arrin[i].number;
				r[i].pubEx=arrex[i].number;
				r[i].userIn=arrin[i].userIn;
				r[i].userEx=arrex[i].userEx;
			}
			return r;
			
		}
		
		public function getGroupInfos():Array {
			return Dao.dp.retriveAll(Structure);
		}
	}
	
}
